﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using GloboTicketAdmin.Mobile.Messages;
using GloboTicketAdmin.Mobile.Models;
using GloboTicketAdmin.Mobile.Services;
using GloboTicketAdmin.Mobile.ViewModels.Base;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GloboTicketAdmin.Mobile.ViewModels
{
    public partial class EventAddEditViewModel : ViewModelBase, IQueryAttributable
    {
        private readonly IEventService _eventService;
        private readonly ICategoryService _categoryService;
        private readonly INavigationService _navigationService;
        private readonly IDialogService _dialogService;
        public EventModel? eventDetail;
        [ObservableProperty]
        private string _pageTitle = default!;
        [ObservableProperty]
        private Guid _id;
        [ObservableProperty]
        [Required(ErrorMessage = "Name is required")]
        [NotifyDataErrorInfo]
        [MinLength(2, ErrorMessage = "Name must be at least 3 characters long")]
        [MaxLength(50, ErrorMessage = "Name cannot exceed 50 characters")]
        private string _name = default!;
        [ObservableProperty]
        //[Range(25,150, ErrorMessage = "Price must be between 25 and 150")]
        private double _price;
        public static ValidationResult ValidatePrice(double price, ValidationContext context)
        {
            if (price < 25 || price > 150)
            {
                return new ValidationResult("Price must be between 25 and 150");
            }
            return ValidationResult.Success!;
        }


        [ObservableProperty]
        private string? _imageUrl = null;
        public static ValidationResult ValidateImageUrl(string? imageUrl, ValidationContext context)
        {
            if (string.IsNullOrWhiteSpace(imageUrl))
            {
                return ValidationResult.Success!;
            }
            if (Uri.TryCreate(imageUrl, UriKind.Absolute, out var uriResult) &&
                (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps))
            {
                return ValidationResult.Success!;
            }
            return new ValidationResult("Invalid URL format");
        }
        [ObservableProperty]
        [Required]
        [NotifyDataErrorInfo]
        private EventStatusEnum _eventStatus;
        [ObservableProperty]
        [Required]
        [NotifyDataErrorInfo]
        private DateTime? _date = DateTime.Now;
        [ObservableProperty]
        [MaxLength(250)]
        private string? _description;
        [ObservableProperty]
        [Required(ErrorMessage = "Category is required")]
        [NotifyDataErrorInfo]
        private CategoryViewModel? _category = new();

        public ObservableCollection<string> Artists { get; set; } = new();
        [ObservableProperty]
        [NotifyCanExecuteChangedFor(nameof(AddArtistCommand))]
        private string addedArtist = default!;
        [ObservableProperty]
        private DateTime _minDate = DateTime.Now;

        public ObservableCollection<ValidationResult> Errors { get; set; } = new();

        public List<EventStatusEnum> StatusList { get; set; } = Enum.GetValues(typeof(EventStatusEnum)).Cast<EventStatusEnum>().ToList();
        public ObservableCollection<CategoryViewModel> Categories { get; set; } = new();
        [RelayCommand(CanExecute = nameof(CanAddArtist))]
        private void AddArtist()
        {
            Artists.Add(AddedArtist);
            AddedArtist = string.Empty;
        }

        private bool CanAddArtist() => !string.IsNullOrWhiteSpace(AddedArtist);

        [RelayCommand(CanExecute = nameof(CanSubmitEvent))]
        private async Task Submit()
        {
            ValidateAllProperties();
            if (HasErrors) return;

            if (Id == Guid.Empty)
            {
                var model = MapDataToEventModel();
                if (await _eventService.CreateEvent(model))
                {
                    WeakReferenceMessenger.Default.Send(new EventAddedOrChangedMessage());
                    await _dialogService.Notify("Success","Event created successfully.");
                    await _navigationService.GoToOverview();
                }
                else
                {
                    await _dialogService.Notify("Failed", "There was an error creating the event. Please try again.");
                }
            }
            else
            {
                var model = MapDataToEventModel();

                if (await _eventService.EditEvent(model))
                {
                    WeakReferenceMessenger.Default.Send(new EventAddedOrChangedMessage());
                    await _dialogService.Notify("Success", "Event updated successfully.");
                    await _navigationService.GoBack();
                }
                else
                {
                    await _dialogService.Notify("Failed", "There was an error updating the event. Please try again.");
                }
            }
        }

        private EventModel MapDataToEventModel()
        {
            var model = new EventModel
            {
                Id = Id == Guid.Empty ? Guid.NewGuid() : Id,
                Name = Name,
                Price = Price,
                ImageUrl = ImageUrl,
                EventStatus = (EventStatusEnum)(int)EventStatus,
                CreateTime = Date ?? DateTime.Now,
                Description = Description,
                Artists = Artists.ToList(),
                Category = new CategoryModel
                {
                    Id = Category?.Id ?? Guid.Empty,
                    Name = Category?.Name ?? string.Empty
                }
            };
            return model;
        }

        private bool CanSubmitEvent() => !HasErrors;

        public EventAddEditViewModel(IEventService eventService, ICategoryService categoryService,INavigationService navigationService,IDialogService dialogService)
        {
            _eventService = eventService;
            _categoryService = categoryService;
            _navigationService = navigationService;
            _dialogService = dialogService;
            ErrorsChanged += AddEventViewModel_ErrorsChanged;
        }

        private void AddEventViewModel_ErrorsChanged(object? sender, DataErrorsChangedEventArgs e)
        {
            Errors.Clear();
            foreach (var error in GetErrors(e.PropertyName ?? string.Empty) ?? Array.Empty<ValidationResult>())
            {
                Errors.Add((ValidationResult)error);
            }
            SubmitCommand.NotifyCanExecuteChanged();
        }

        public override async Task LoadAsync()
        {
            await Loading(
                async () =>
                {
                    var categories = await _categoryService.GetCategories();
                    MapCategories(categories);
                    if (eventDetail is null && Id != Guid.Empty)
                    { eventDetail = await _eventService.GetEvent(Id); }
                    MapEvent(eventDetail);

                    ValidateAllProperties();
                });
        }

        private void MapCategories(List<CategoryModel> categories)
        {
            foreach (var category in categories)
            {
                Categories.Add(new CategoryViewModel() { Id = category.Id, Name = category.Name });
            }

        }

        private void MapEvent(EventModel @event)
        {
            if (@event is null)
            {
                PageTitle = "Add Event";
                Id = Guid.Empty;
                Name = string.Empty;
                Price = 0;
                ImageUrl = null;
                EventStatus = EventStatusEnum.OnSale;
                Date = DateTime.Now;
                Description = string.Empty;
                Artists.Clear();
                Category = Categories.FirstOrDefault();
                return;
            }
            else
            {
                PageTitle = "Edit Event";
                Id = @event.Id;
                Name = @event.Name;
                Price = @event.Price;
                ImageUrl = @event.ImageUrl;
                EventStatus = (EventStatusEnum)@event.EventStatus;
                Date = @event.CreateTime;
                Description = @event.Description;
                Artists = new ObservableCollection<string>(@event.Artists);
                Category = new CategoryViewModel
                {
                    Id = @event.Category.Id,
                    Name = @event.Category.Name
                };
            }

        }

        public void ApplyQueryAttributes(IDictionary<string, object> query)
        {
            if (query.Count > 0)
            {
                eventDetail = query["Event"] as EventModel;
            }
        }
    }
}
